/*******************************************************************************
 * Copyright (c) 2010-2011 Robert Fraser                                       *
 *                                                                             *
 * Permission is hereby granted, free of charge, to any person obtaining a     *
 * copy of this software and associated documentation files (the "Software"),  *
 * to deal in the Software without restriction, including without limitation   *
 * the rights to use, copy, modify, merge, publish, distribute, sublicense,    *
 * and/or sell copies of the Software, and to permit persons to whom the       *
 * Software is furnished to do so, subject to the following conditions:        *
 *                                                                             *
 *   - The above copyright notice and this permission notice shall be included *
 *     in all copies or substantial portions of the Software.                  *
 *                                                                             *
 * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR  *
 * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,    *
 * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE *
 * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER      *
 * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING     *
 * FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER         *
 * DEALINGS IN THE SOFTWARE.                                                   *
 *******************************************************************************/

using System.Windows;
using System.Windows.Media;
using zeal.util;

namespace zeal.ui.graph
{
    internal partial class BezierPath : FrameworkElement
    {
        private readonly StreamGeometry _geometry;
        private bool _shouldDraw;

        public BezierPath()
        {
            _geometry = new StreamGeometry();
            IsHitTestVisible = false;
            Focusable = false;
        }

        protected override void OnRender(DrawingContext drawingContext)
        {
            // For performance reasons, this needs to be rendered directly rather than using the Path object in System.Windows.Shapes
            if (Pen == null || !_shouldDraw)
                return;
            drawingContext.DrawGeometry(null, Pen, _geometry);
        }

        private void onRouteChanged()
        {
            Point src = Source;
            Point dst = Destination;
            if (!src.X.isValid() || !src.Y.isValid() || !dst.X.isValid() || !dst.Y.isValid())
            {
                _shouldDraw = false;
                return;
            }

            /*
            * The control points are all laid out along midpoint lines, something like this:
            * 
            *   -------------------------------- 
            *  |          |          |          |
            *  |   SRC    |    CP1   |          |
            *  |          |          |          |
            *   -------------------------------- 
            *  |          |          |          |
            *  |          |    MID   |          |
            *  |          |          |          |
            *   ------------------------------- 
            *  |          |          |          |
            *  |          |    CP2   |    DST   |
            *  |          |          |          |
            *   -------------------------------- 
            *   
            * This causes it to be horizontal at the endpoints and vertical
            * at the midpoint.
            */

            double mx = (src.X + dst.X) / 2;
            double my = (src.Y + dst.Y) / 2;
            Point mid = new Point(mx, my);
            Point cp1 = new Point(mx, src.Y);
            Point cp2 = new Point(mx, dst.Y);
            
            _geometry.Clear();
            _shouldDraw = true;
            using(StreamGeometryContext ctx = _geometry.Open())
            {
                ctx.BeginFigure(src, false, false);
                ctx.QuadraticBezierTo(cp1, mid, true, false);
                ctx.QuadraticBezierTo(cp2, dst, true, false);
            }
        }
    }
}